package cn.htsyb.synergy.tester.runner;

import cn.htsyb.synergy.tester.frame.WebDriverMgr;
import cn.htsyb.synergy.tester.model.CaseBean;
import cn.htsyb.synergy.tester.model.OperateBean;
import cn.htsyb.synergy.tester.model.PlatBean;
import cn.htsyb.synergy.tester.model.StepBean;
import org.apache.commons.lang.ClassUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang.reflect.MethodUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Map;
import java.util.TreeMap;

public class InvokeRunner implements IRunner {
    private static final Log defLog = LogFactory.getLog(InvokeRunner.class);
    private static TreeMap<String, OperateBean> operatesMap;
    private static ArrayList<CaseBean> testCasesList;
    private static Map<String, String> globalElementMap;
    private static Map<String, Object> globalParamMap;

    @Override
    public void execPlat(PlatBean platBean) {

        operatesMap = PlatBean.getOperatesMap();
        testCasesList = PlatBean.getTestCasesMap();
        globalElementMap = PlatBean.getGlobalElementMap();
        globalParamMap = PlatBean.getGlobalParamMap();

        //String repPath = ResourceUtil..convertToLocalPath(PathUtil.getClassPath() + File.separator + ".." + File.separator;
        //ExtentReports extentRep = new ExtentReports(repPath + "extent.html", false, NetworkMode.OFFLINE, new Locale("cn"));


        //ExtentTest platExtent = extentRep.createTest("plat");

        for (CaseBean caseBean : testCasesList) {
            try {

               //ExtentTest testExtent = extentRep.createTest(caseBean.getDescribe());
                for (Map<String, Object> caseParamMap : caseBean.getParames()) {
                    defLog.info("迭代参数组" + caseParamMap.toString() + "执行测试步骤");
                    int srotno = 0;// 记录步骤
                    String paramDesc = (String) caseParamMap.get("desc");
                    paramDesc = StringUtils.isNotEmpty(paramDesc) ? paramDesc : "迭代参数";

                    //ExtentTest paramExtent = extentRep.createTest(paramDesc, caseParamMap.toString());

                    for (StepBean stepBean : caseBean.getSteps()) {
                        try {
                            srotno++;
                            if (stepBean == null) {
                                break;
                            }
                            defLog.debug("【" + srotno + "】开始解析步骤：" + stepBean);
                            OperateBean opreaBean = operatesMap.get(stepBean.getOperate());
                            if (opreaBean == null) {
                                String errmsg = "操作指令[" + stepBean.getOperate() + "]无法识别";
                                throw new Exception(errmsg);
                            }
                            Object[] params = handTagVal(stepBean.getParams(), caseParamMap, caseBean.getElements());
                            defLog.info("【" + srotno + "】开始执行步骤：" + stepBean);
                            Class<?> cls = ClassUtils.getClass(opreaBean.getClazz());

                            Object result = MethodUtils.invokeExactStaticMethod(cls, opreaBean.getMethod(), params);

                            String store = stepBean.getStore();
                            if (StringUtils.isNotEmpty(store)) {
                                String storeName = getParamStr(store);
                                caseParamMap.put(storeName, result.toString());
                            }

                            //paramExtent.log(LogStatus.PASS, "【" + srotno + "】步骤：" + stepBean.toString() + "执行成功" + "返回：" + (result != null ? result.toString() : ""));
                        } catch (InvocationTargetException e) {
                            Throwable exce = ExceptionUtils.getRootCause(e);

                            //paramExtent.log(LogStatus.FAIL, "【" + srotno + "】步骤：" + stepBean.toString() + "执行失败,失败原因参考：\n" + ExceptionUtils.getFullStackTrace(e));//,
                            //paramExtent.addScreenCapture(repPath + RandomStringUtils.random(8) + ".png"));
                            defLog.error("步骤执行失败,失败原因参考\n" + ExceptionUtils.getFullStackTrace(exce));

                        } catch (Exception e) {

                            //paramExtent.log(LogStatus.FAIL, "【" + srotno + "】步骤：" + stepBean.toString() + "执行失败,失败原因参考：\n" + ExceptionUtils.getFullStackTrace(e));//,
                            //MediaEntityBuilder.createScreenCaptureFromPath(repPath + RandomStringUtils.random(8) + ".png").build());
                            defLog.error("步骤执行失败,失败原因参考\n" + ExceptionUtils.getFullStackTrace(e));
                            throw e;
                        }

                    }
                    //testExtent..appendChild(paramExtent);
                }
                //platExtent.appendChild(testExtent);
            } catch (Exception e) {
                defLog.error("case执行失败,失败原因参考\n" + ExceptionUtils.getFullStackTrace(e));
            } finally {
                WebDriverMgr.removeDriver();
            }
        }

       // extentRep.flush();
    }

    public Object[] handTagVal(Object[] params, Map<String, Object> caseParamMap, Map<String, Object> caseElementMap) throws Exception {
        if (params != null) {
            for (int i = 0; i < params.length; i++) {
                String paramStr = (String) params[i];
                Object tagParam = null;
                if (paramStr.startsWith("@P{") && paramStr.endsWith("}")) {
                    tagParam = handTagParam(paramStr, caseParamMap);
                    params[i] = tagParam;
                } else if (paramStr.startsWith("@E{") && paramStr.endsWith("}")) {
                    tagParam = handTagElement(paramStr, caseElementMap);
                    params[i] = tagParam;
                }

            }
        }
        return params;
    }

    public Object handTagElement(String paramStr, Map<String, Object> caseElementMap) throws Exception {
        paramStr = getParamStr(paramStr);
        Object tagParam = null;
        if (caseElementMap != null) {
            tagParam = caseElementMap.get(paramStr);
        }
        if (globalElementMap != null && tagParam == null) {
            tagParam = globalElementMap.get(paramStr);
        }
        if (tagParam == null) {
            String errMsg = "元素引用变量[" + paramStr + "]无法解析到实际值，当前case元素对象：" + caseElementMap + ",公共元素对象:" + globalElementMap;
            throw new Exception(errMsg);
        }
        return tagParam;
    }

    public Object handTagParam(String paramStr, Map<String, Object> caseParamMap) throws Exception {
        paramStr = getParamStr(paramStr);
        Object tagParam = null;
        if (caseParamMap != null) {
            tagParam = caseParamMap.get(paramStr);
        }
        if (globalParamMap != null && tagParam == null) {
            tagParam = globalParamMap.get(paramStr);
        }
        if (tagParam == null) {
            String errMsg = "参数引用变量[" + paramStr + "]无法解析到实际值，当前case参数对象：" + caseParamMap.toString() + ",公共参数对象:" + globalParamMap.toString();
            throw new Exception(errMsg);
        }
        return tagParam;
    }

    public String getParamStr(String paramStr) {
        return paramStr.substring(3, paramStr.length() - 1);
    }

}
